/*
 * Copyright (c) 2023 HPMicro
 *
 * SPDX-License-Identifier: BSD-3-Clause
 *
 */

#include <stdio.h>
#include "board.h"
#include "hpm_sysctl_drv.h"
#include "hpm_gptmr_drv.h"
#include "hpm_debug_console.h"
#include "hpm_gptmr_drv.h"
#include "hpm_pwm_drv.h"
#if (defined (DMA_SOC_MAX_COUNT) && (DMA_SOC_MAX_COUNT == 2)) && (defined (CONFIG_USE_DMA) && (CONFIG_USE_DMA == 1))
#include "hpm_dmamux_drv.h"
#ifdef HPMSOC_HAS_HPMSDK_DMAV2
#include "hpm_dmav2_drv.h"
#else
#include "hpm_dma_drv.h"
#endif
#endif

#define APP_BOARD_PWM                          HPM_GPTMR5         //BOARD_GPTMR_PWM
#define APP_BOARD_PWM_CH                                2         //BOARD_GPTMR_PWM_CHANNEL
#define APP_BOARD_GPTMR_CLOCK                clock_gptmr5         //BOARD_GPTMR_PWM_CLK_NAME
#define APP_IRQN                              IRQn_GPTMR5
uint32_t cmp;

#define APP_BOARD_GPTMR               BOARD_GPTMR
#define BOARD_GPTMR_CH0               0
#define BOARD_GPTMR_CH1               BOARD_GPTMR_CHANNEL

#define APP_BOARD_GPTMR_CLOCK         BOARD_GPTMR_CLK_NAME

#if (defined (DMA_SOC_MAX_COUNT) && (DMA_SOC_MAX_COUNT == 2)) && (defined (CONFIG_USE_DMA) && (CONFIG_USE_DMA == 1))
/* XDMA is 64bit width.so can transfer gptmr two 32bit register,it's include CAPPRD, CAPDTY. */
#define APP_GPTMR_DMA                 BOARD_APP_XDMA
#define APP_GPTMR_DMA_IRQ             BOARD_APP_XDMA_IRQ
#define APP_DMA_SRC_WIDTH             DMA_TRANSFER_WIDTH_DOUBLE_WORD
#define APP_DMA_DST_WIDTH             DMA_TRANSFER_WIDTH_DOUBLE_WORD

#define APP_GPTMR_DMA_SRC_CH0         BOARD_GPTMR_DMA_SRC
#define APP_GPTMR_DMA_SRC_CH1         HPM_DMA_SRC_GPTMR4_0
#define APP_DMA_CH0                    (0U)
#define APP_DMA_CH1                    (1U)
#define APP_DMAMUX_CH0                 DMA_SOC_CHN_TO_DMAMUX_CHN(APP_GPTMR_DMA, APP_DMA_CH0)
#define APP_DMAMUX_CH1                 DMA_SOC_CHN_TO_DMAMUX_CHN(APP_GPTMR_DMA, APP_DMA_CH1)

#define APP_MEASURE_COUNT             (10U)

typedef struct {
    uint32_t priiod;
    uint32_t duty;
} pwm_measure_cfg_t;

static void dma_transfer_config(void);

ATTR_PLACE_AT_NONCACHEABLE_WITH_ALIGNMENT(4) pwm_measure_cfg_t pwm_meas_table[APP_MEASURE_COUNT];
ATTR_PLACE_AT_NONCACHEABLE_WITH_ALIGNMENT(4) pwm_measure_cfg_t my_pwm_meas_table[APP_MEASURE_COUNT];

volatile uint32_t count;
volatile bool     ch0_dma_is_done;
volatile bool     ch1_dma_is_done;
dma_channel_config_t ch1_config = {0};
dma_channel_config_t ch0_config = {0};

void isr_dma(void)
{
    volatile hpm_stat_t stat;
    stat = dma_check_transfer_status(APP_GPTMR_DMA, APP_DMA_CH0);
    if (stat & DMA_CHANNEL_STATUS_TC) {
        gptmr_clear_status(APP_BOARD_GPTMR, GPTMR_CH_RLD_STAT_MASK(BOARD_GPTMR_CH1));
        ch0_dma_is_done = true;
    }

    stat = dma_check_transfer_status(APP_GPTMR_DMA,APP_DMA_CH1);
    if(stat & DMA_CHANNEL_STATUS_TC){
        gptmr_clear_status(APP_BOARD_GPTMR,GPTMR_CH_RLD_STAT_MASK(BOARD_GPTMR_CH0));
        ch1_dma_is_done = true;
    }
}
SDK_DECLARE_EXT_ISR_M(APP_GPTMR_DMA_IRQ, isr_dma)
#endif
void init_trigger_source(PWM_Type *ptr,uint32_t freq,uint8_t channel);
void init_gptmr_pin(GPTMR_Type *ptr);
static void set_pwm_waveform_edge_aligned_frequency(uint32_t freq);
void init_trigger_mux(TRGM_Type * ptr);

static void pwm_measure_config(void);
volatile uint32_t gptmr_freq;



void start_measure(void)
{
    memset(pwm_meas_table,0,sizeof(pwm_meas_table));
    memset(my_pwm_meas_table,0,sizeof(my_pwm_meas_table));/* 每次搬运开始时，清除上次采样结果 */

    dma_disable_channel(APP_GPTMR_DMA, APP_DMA_CH0);
    dma_disable_channel(APP_GPTMR_DMA, APP_DMA_CH1);
    
    dma_reset(APP_GPTMR_DMA);

    dma_setup_channel(APP_GPTMR_DMA, APP_DMA_CH0, &ch1_config, false);
    dma_setup_channel(APP_GPTMR_DMA, APP_DMA_CH1, &ch0_config, false);

    dma_enable_channel(APP_GPTMR_DMA, APP_DMA_CH0);
    dma_enable_channel(APP_GPTMR_DMA,APP_DMA_CH1);

    /* 以上是重新配置DMA，让其重新开始搬运 */
}
int main(void)
{
    board_init();
    HPM_IOC->PAD[IOC_PAD_PE25].FUNC_CTL = IOC_PE25_FUNC_CTL_GPTMR4_CAPT_1;/* 初始化GPTMR4的外部输入引脚1 */
    HPM_IOC->PAD[IOC_PAD_PE21].FUNC_CTL = IOC_PE21_FUNC_CTL_GPTMR4_CAPT_0;/* 初始化GPTMR4的外部输入引脚0 */

#if (defined (DMA_SOC_MAX_COUNT) && (DMA_SOC_MAX_COUNT == 2)) && (defined (CONFIG_USE_DMA) && (CONFIG_USE_DMA == 1))
    dma_transfer_config();
#endif
    init_gptmr_pin(HPM_GPTMR5);
    init_trigger_source(HPM_PWM2,300000,8);/* PD25 300K */
    set_pwm_waveform_edge_aligned_frequency(200000); /* */

    init_trigger_mux(HPM_TRGM2);
    pwm_start_counter(HPM_PWM2);


    pwm_measure_config();
    while (1) {
        printf("please press any key to start PWM measure\r\n");
        getchar();
        /* please make sure deplay time is more than one pwm cycle */
        start_measure();
        
        while (1) {
            if(ch0_dma_is_done&&ch1_dma_is_done)//只有DMA通道0、1同时搬运完成后，才算本次搬运完成。
            {
                ch0_dma_is_done = false;
                ch1_dma_is_done = false;
                printf("channel 0 cap data : \r\n");
                
                for (uint32_t i = 0; i < sizeof(pwm_meas_table) / sizeof(pwm_measure_cfg_t); i++) {
                    printf("[table_%d]measured frequency: %f\n", i, (float) gptmr_freq / pwm_meas_table[i].priiod);
                    printf("[table_%d]measured duty cycle: %.2f%%\n", i, ((float) pwm_meas_table[i].duty / pwm_meas_table[i].priiod) * 100);
                }
                
                printf("channel 1 cap data : \r\n");
                for (uint32_t i = 0; i< sizeof(my_pwm_meas_table) / sizeof(pwm_measure_cfg_t); i++) {
                    printf("[table_%d]measured frequency: %f\n", i ,(float) gptmr_freq / my_pwm_meas_table[i].priiod);
                    printf("[table_%d]measured duty cycle: %.2f%%\n", i, ((float) my_pwm_meas_table[i].duty / my_pwm_meas_table[i].priiod) * 100);
                }
                printf("\r\n");
                break;
            }
        }
    }
    return 0;
}

#if (defined (DMA_SOC_MAX_COUNT) && (DMA_SOC_MAX_COUNT == 2)) && (defined (CONFIG_USE_DMA) && (CONFIG_USE_DMA == 1))
static void dma_transfer_config(void)
{
    dma_disable_channel(APP_GPTMR_DMA, APP_DMA_CH0);
    dma_disable_channel(APP_GPTMR_DMA, APP_DMA_CH1);
    
    dma_reset(APP_GPTMR_DMA);

    dma_default_channel_config(APP_GPTMR_DMA, &ch1_config);
    ch1_config.src_addr = (uint32_t)&APP_BOARD_GPTMR->CHANNEL[BOARD_GPTMR_CH1].CAPPRD;/* CAPPRD寄存器和CAPDTY寄存器是相邻的，一同传输64位就行 */
    ch1_config.dst_addr = core_local_mem_to_sys_address(HPM_CORE0, (uint32_t)&pwm_meas_table[0].priiod);/* 目的地址同理，pwm_meas_table是64位的 */
    ch1_config.src_mode = DMA_HANDSHAKE_MODE_HANDSHAKE;/* 只有接收到下一次请求，才搬运下一次数据 */
    ch1_config.src_width = APP_DMA_SRC_WIDTH;/* 源地址宽度 */
    ch1_config.src_addr_ctrl = DMA_ADDRESS_CONTROL_FIXED;/* 源地址不自增 */
    ch1_config.src_burst_size = DMA_NUM_TRANSFER_PER_BURST_1T;/* 一次触发搬运一次数据 */
    ch1_config.dst_width = APP_DMA_DST_WIDTH;/* 目的地址宽度 */
    ch1_config.dst_addr_ctrl = DMA_ADDRESS_CONTROL_INCREMENT;/* 目的地址自增 */
    ch1_config.dst_mode = DMA_HANDSHAKE_MODE_NORMAL;/* 普通模式 */
    ch1_config.size_in_byte = sizeof(pwm_meas_table);
    if (status_success != dma_setup_channel(APP_GPTMR_DMA, APP_DMA_CH0, &ch1_config, false)) {
        printf(" dma setup channel failed\n");
        return;
    }

    dma_default_channel_config(APP_GPTMR_DMA, &ch0_config);
    ch0_config.src_addr = (uint32_t)&APP_BOARD_GPTMR->CHANNEL[BOARD_GPTMR_CH0].CAPPRD;
    ch0_config.dst_addr = core_local_mem_to_sys_address(HPM_CORE0, (uint32_t)&my_pwm_meas_table[0].priiod);
    ch0_config.src_mode = DMA_HANDSHAKE_MODE_HANDSHAKE;
    ch0_config.src_width = APP_DMA_SRC_WIDTH;
    ch0_config.src_addr_ctrl = DMA_ADDRESS_CONTROL_FIXED;
    ch0_config.src_burst_size = DMA_NUM_TRANSFER_PER_BURST_1T;
    ch0_config.dst_width = APP_DMA_DST_WIDTH;
    ch0_config.dst_addr_ctrl = DMA_ADDRESS_CONTROL_INCREMENT;
    ch0_config.dst_mode = DMA_HANDSHAKE_MODE_NORMAL;
    ch0_config.size_in_byte = sizeof(my_pwm_meas_table);

    if (status_success != dma_setup_channel(APP_GPTMR_DMA, APP_DMA_CH1, &ch0_config, false)) {
        printf(" dma setup channel failed\n");
        return;
    }
}
#endif

static void pwm_measure_config(void)
{
    gptmr_channel_config_t config;
    gptmr_channel_get_default_config(APP_BOARD_GPTMR, &config);
    gptmr_freq = clock_get_frequency(APP_BOARD_GPTMR_CLOCK);
#if (defined (DMA_SOC_MAX_COUNT) && (DMA_SOC_MAX_COUNT == 2)) && (defined (CONFIG_USE_DMA) && (CONFIG_USE_DMA == 1))

    gptmr_stop_counter(APP_BOARD_GPTMR, BOARD_GPTMR_CH0);
    gptmr_stop_counter(APP_BOARD_GPTMR, BOARD_GPTMR_CH1);/* 停止GPTMR计数 */

    config.cmp_initial_polarity_high = false;
    config.dma_request_event = gptmr_dma_request_on_input_signal_toggle;/* 输入捕获信号发生反转的时候产生DMA请求 */
    config.mode = gptmr_work_mode_measure_width;/* 脉宽测量 */
    
    gptmr_channel_enable_dma_request(APP_BOARD_GPTMR, BOARD_GPTMR_CH0, false);
    gptmr_channel_enable_dma_request(APP_BOARD_GPTMR, BOARD_GPTMR_CH1, false);/* 使能GPTMR通道DMA请求 */
    
    dmamux_config(BOARD_APP_DMAMUX, APP_DMAMUX_CH0, APP_GPTMR_DMA_SRC_CH0, true);
    dmamux_config(BOARD_APP_DMAMUX, APP_DMAMUX_CH1, APP_GPTMR_DMA_SRC_CH1, true);/* 连接DMA请求与DMA通道 */

    intc_m_enable_irq_with_priority(APP_GPTMR_DMA_IRQ, 4);
#else
    config.mode = gptmr_work_mode_measure_width;
#endif
    gptmr_channel_config(APP_BOARD_GPTMR, BOARD_GPTMR_CH0, &config, false);
    gptmr_channel_config(APP_BOARD_GPTMR, BOARD_GPTMR_CH1, &config, false);/* 配置GPTMR通道 */
    
    gptmr_channel_reset_count(APP_BOARD_GPTMR, BOARD_GPTMR_CH0);
    gptmr_channel_reset_count(APP_BOARD_GPTMR, BOARD_GPTMR_CH1);

    gptmr_start_counter(APP_BOARD_GPTMR, BOARD_GPTMR_CH0);
    gptmr_start_counter(APP_BOARD_GPTMR, BOARD_GPTMR_CH1);
}

/* 以下是生成PWM的代码↓ */

void init_trigger_source(PWM_Type *ptr,uint32_t freq,uint8_t channel)
{
    pwm_cmp_config_t pwm_cmp_cfg;
    pwm_output_channel_t pwm_output_ch_cfg;

    /* TODO: Set PWM Clock Source and divider */
    
    /* 33.33KHz reload at 200MHz */ //默认未经修改的PWM时钟频率是200MHz
    pwm_set_reload(ptr, 0, (200000000 / freq)-1);

    /* Set a comparator */
    memset(&pwm_cmp_cfg, 0, sizeof(pwm_cmp_config_t));
    pwm_cmp_cfg.enable_ex_cmp  = false;
    pwm_cmp_cfg.mode           = pwm_cmp_mode_output_compare;
    pwm_cmp_cfg.update_trigger = pwm_shadow_register_update_on_shlk;

    /* Select comp8 and trigger at the middle of a pwm cycle */
    
    pwm_cmp_cfg.cmp = (200000000 / freq)/2;
    pwm_config_cmp(ptr, channel, &pwm_cmp_cfg);//设置cmp寄存器

    /* Issue a shadow lock */
    pwm_issue_shadow_register_lock_event(ptr);

    /* Set comparator channel to generate a trigger signal */
    pwm_output_ch_cfg.cmp_start_index = channel;   /* start channel */ //将cmp寄存器绑定在某个通道
    pwm_output_ch_cfg.cmp_end_index   = channel;   /* end channel */ //将cmp寄存器绑定在某个通道
    pwm_output_ch_cfg.invert_output   = false;
    pwm_config_output_channel(ptr, channel, &pwm_output_ch_cfg); //将第channel寄存器绑定在第channel输出通道

    /* Start the comparator counter */
}

void init_trigger_mux(TRGM_Type * ptr)
{
    trgm_output_t trgm_output_cfg;

    trgm_output_cfg.invert = false;
    trgm_output_cfg.type = trgm_output_same_as_input;

    HPM_IOC->PAD[IOC_PAD_PD25].FUNC_CTL = IOC_PD25_FUNC_CTL_TRGM2_P_08;
    trgm_enable_io_output(HPM_TRGM2, 1 << 8);

    trgm_output_cfg.input  = HPM_TRGM2_INPUT_SRC_PWM2_CH8REF;
    trgm_output_config(ptr, TRGM_TRGOCFG_ADC0_STRGI, &trgm_output_cfg);
    trgm_output_config(ptr, TRGM_TRGOCFG_ADC1_STRGI, &trgm_output_cfg);
    trgm_output_config(ptr, TRGM_TRGOCFG_ADC2_STRGI, &trgm_output_cfg);
    trgm_output_config(ptr,TRGM_TRGOCFG_ADC3_STRGI,&trgm_output_cfg);/*触发ADC，选择不删*/
    trgm_output_config(ptr, HPM_TRGM2_OUTPUT_SRC_TRGM2_P8, &trgm_output_cfg);
}


/**
 * @brief set waveform edge aligned pwm duty
 *
 * @param [in] duty pwm duty, the value range is 1 to 100
 */
void init_gptmr_pin(GPTMR_Type *ptr)
{
     /* TMR5 capture 2 */
     HPM_IOC->PAD[IOC_PAD_PD19].FUNC_CTL = IOC_PD19_FUNC_CTL_TRGM2_P_09;
     trgm_enable_io_output(HPM_TRGM2, 1 << 9);
     
     trgm_output_t trgm2IoConfig0;
     trgm2IoConfig0.invert = 0;
     trgm2IoConfig0.type = trgm_output_same_as_input;
     trgm2IoConfig0.input = HPM_TRGM2_INPUT_SRC_GPTMR5_OUT2;
     trgm_output_config(HPM_TRGM2, HPM_TRGM2_OUTPUT_SRC_TRGM2_P9, &trgm2IoConfig0);
}

static void set_pwm_waveform_edge_aligned_frequency(uint32_t freq)
{
    gptmr_channel_config_t config;
    uint32_t gptmr_freq;
    uint32_t current_reload;
    gptmr_channel_get_default_config(APP_BOARD_PWM, &config);

    gptmr_freq = clock_get_frequency(APP_BOARD_GPTMR_CLOCK);
    printf("gptmr_freq = %d\r\n",gptmr_freq);
    current_reload = gptmr_freq / (freq) - 1;
    config.reload = current_reload;

    config.cmp[0] = current_reload/2;

    config.cmp_initial_polarity_high = false;//PWM开始的电平，false为低电平

    gptmr_stop_counter(APP_BOARD_PWM, APP_BOARD_PWM_CH);
    gptmr_channel_config(APP_BOARD_PWM, APP_BOARD_PWM_CH, &config, false);
    gptmr_channel_reset_count(APP_BOARD_PWM, APP_BOARD_PWM_CH);

    gptmr_start_counter(APP_BOARD_PWM, APP_BOARD_PWM_CH);

    gptmr_channel_select_synci_valid_edge(APP_BOARD_PWM,APP_BOARD_PWM_CH,gptmr_synci_edge_rising);

}